/**
 *******************************************************************************
 * @file  usb_host_hid_keyboardapp.c
 * @brief The application layer for USB Host HID Keyboard handling
 @verbatim
   Change Logs:
   Date             Author          Notes
   2022-03-31       CDT             First version
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2022, Xiaohua Semiconductor Co., Ltd. All rights reserved.
 *
 * This software component is licensed by XHSC under BSD 3-Clause license
 * (the "License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                    opensource.org/licenses/BSD-3-Clause
 *
 *******************************************************************************
 */

/*******************************************************************************
 * Include files
 ******************************************************************************/
#include "usb_host_hid_keyboardapp.h"
#include "usb_host_user.h"

/**
 * @addtogroup LL_USB_LIB
 * @{
 */

/**
 * @addtogroup LL_USB_HOST_CLASS
 * @{
 */

/**
 * @addtogroup LL_USB_HOST_HID
 * @{
 */

/*******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/*******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/

/*******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/
void keyboard_init(void);
void keyboard_decode(uint8_t *pbuf);

/*******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/
#ifdef USB_INTERNAL_DMA_ENABLED
#if defined   (__CC_ARM) /*!< ARM Compiler */
__align(4)
#elif defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#elif defined (__GNUC__) /*!< GNU Compiler */
#pragma pack(4)
#endif /* __CC_ARM */
#endif

HID_cb_TypeDef HID_KEYBRD_cb = {
    keyboard_init,
    keyboard_decode
};

/*******************************************************************************
 * Local variable definitions ('static')
 ******************************************************************************/
static  const  uint8_t  HID_KEYBRD_Codes[] = {
    0,      0,      0,      0,      31,     50,     48,     33,
    19,     34,     35,     36,     24,     37,     38,     39,     /* 0x00 - 0x0F */
    52,     51,     25,     26,     17,     20,     32,     21,
    23,     49,     18,     47,     22,     46,     2,      3,      /* 0x10 - 0x1F */
    4,      5,      6,      7,      8,      9,      10,     11,
    43,     110,    15,     16,     61,     12,     13,     27,     /* 0x20 - 0x2F */
    28,     29,     42,     40,     41,     1,      53,     54,
    55,     30,     112,    113,    114,    115,    116,    117,    /* 0x30 - 0x3F */
    118,    119,    120,    121,    122,    123,    124,    125,
    126,    75,     80,     85,     76,     81,     86,     89,     /* 0x40 - 0x4F */
    79,     84,     83,     90,     95,     100,    105,    106,
    108,    93,     98,     103,    92,     97,     102,    91,     /* 0x50 - 0x5F */
    96,     101,    99,     104,    45,     129,    0,      0,
    0,      0,      0,      0,      0,      0,      0,      0,      /* 0x60 - 0x6F */
    0,      0,      0,      0,      0,      0,      0,      0,
    0,      0,      0,      0,      0,      0,      0,      0,      /* 0x70 - 0x7F */
    0,      0,      0,      0,      0,      107,    0,      56,
    0,      0,      0,      0,      0,      0,      0,      0,      /* 0x80 - 0x8F */
    0,      0,      0,      0,      0,      0,      0,      0,
    0,      0,      0,      0,      0,      0,      0,      0,      /* 0x90 - 0x9F */
    0,      0,      0,      0,      0,      0,      0,      0,
    0,      0,      0,      0,      0,      0,      0,      0,      /* 0xA0 - 0xAF */
    0,      0,      0,      0,      0,      0,      0,      0,
    0,      0,      0,      0,      0,      0,      0,      0,      /* 0xB0 - 0xBF */
    0,      0,      0,      0,      0,      0,      0,      0,
    0,      0,      0,      0,      0,      0,      0,      0,      /* 0xC0 - 0xCF */
    0,      0,      0,      0,      0,      0,      0,      0,
    0,      0,      0,      0,      0,      0,      0,      0,      /* 0xD0 - 0xDF */
    58,     44,     60,     127,    64,     57,     62,     128     /* 0xE0 - 0xE7 */
};

#ifdef QWERTY_KEYBOARD
static  const  uint8_t  HID_KEYBRD_Key[] = {
    '\0',   '`',   '1',   '2',   '3',   '4',   '5',   '6',
    '7',   '8',   '9',   '0',   '-',   '=',   '\0',   '\r',
    '\t',   'q',   'w',   'e',   'r',   't',   'y',   'u',
    'i',   'o',   'p',   '[',   ']',   '\\',
    '\0',   'a',   's',   'd',   'f',   'g',   'h',   'j',
    'k',   'l',   ';',   '\'',   '\0',   '\n',
    '\0',   '\0',   'z',   'x',   'c',   'v',   'b',   'n',
    'm',   ',',   '.',   '/',   '\0',   '\0',
    '\0',   '\0',   '\0',   ' ',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\r',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '7',   '4',   '1',
    '\0',   '/',    '8',   '5',   '2',
    '0',   '*',    '9',   '6',   '3',
    '.',   '-',    '+',   '\0',   '\n',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0'
};

static  const  uint8_t  HID_KEYBRD_ShiftKey[] = {
    '\0',   '~',   '!',   '@',   '#',   '$',   '%',   '^',   '&',   '*',   '(',   ')',
    '_',   '+',   '\0',   '\0',   '\0',   'Q',   'W',   'E',   'R',   'T',   'Y',   'U',
    'I',   'O',   'P',   '{',   '}',   '|',   '\0',   'A',   'S',   'D',   'F',   'G',
    'H',   'J',   'K',   'L',   ':',   '"',   '\0',   '\n',   '\0',   '\0',   'Z',   'X',
    'C',   'V',   'B',   'N',   'M',   '<',   '>',   '?',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0'
};

#else

static  const  uint8_t  HID_KEYBRD_Key[] = {
    '\0',   '`',   '1',   '2',   '3',   '4',   '5',   '6',   '7',   '8',   '9',   '0',
    '-',   '=',   '\0',   '\r',   '\t',   'a',   'z',   'e',   'r',   't',   'y',   'u',
    'i',   'o',   'p',   '[',   ']',   '\\',   '\0',   'q',   's',   'd',   'f',   'g',
    'h',   'j',   'k',   'l',   'm',   '\0',   '\0',   '\n',   '\0',   '\0',   'w',   'x',
    'c',   'v',   'b',   'n',   ',',   ';',   ':',   '!',   '\0',   '\0',   '\0',   '\0',
    '\0',   ' ',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\r',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '7',   '4',   '1',   '\0',   '/',
    '8',   '5',   '2',   '0',   '*',   '9',   '6',   '3',   '.',   '-',   '+',   '\0',
    '\n',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0'
};

static  const  uint8_t  HID_KEYBRD_ShiftKey[] = {
    '\0',   '~',   '!',   '@',   '#',   '$',   '%',   '^',   '&',   '*',   '(',   ')',   '_',
    '+',   '\0',   '\0',   '\0',   'A',   'Z',   'E',   'R',   'T',   'Y',   'U',   'I',   'O',
    'P',   '{',   '}',   '*',   '\0',   'Q',   'S',   'D',   'F',   'G',   'H',   'J',   'K',
    'L',   'M',   '%',   '\0',   '\n',   '\0',   '\0',   'W',   'X',   'C',   'V',   'B',   'N',
    '?',   '.',   '/',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0'
};
#endif

/**
 * @brief  Initialize the keyboard function.
 * @param  None
 * @retval None
 */
void keyboard_init(void)
{
    user_keyboard_init();
}

/**
 * @brief   The function is to decode the pressed keys when receives key value.
 * @param  [in] pbuf        buffer contain the HID IN report data.
 * @retval None
 */
void keyboard_decode(uint8_t *pbuf)
{
    static  uint8_t   shift;
    static  uint8_t   keys[KBR_MAX_NBR_PRESSED];
    static  uint8_t   keys_new[KBR_MAX_NBR_PRESSED];
    static  uint8_t   keys_last[KBR_MAX_NBR_PRESSED];
    static  uint8_t   key_newest;
    static  uint8_t   nbr_keys;
    static  uint8_t   nbr_keys_new;
    static  uint8_t   nbr_keys_last;
    uint8_t   ix;
    uint8_t   jx;
    uint8_t   error;
    uint8_t   output;

    nbr_keys      = 0U;
    nbr_keys_new  = 0U;
    nbr_keys_last = 0U;
    key_newest    = 0U;

    /* Check if Shift key is pressed */
    if ((pbuf[0] == KBD_LEFT_SHIFT) || (pbuf[0] == KBD_RIGHT_SHIFT)) {
        shift = TRUE;
    } else {
        shift = FALSE;
    }

    error = FALSE;
    /* Check for the value of pressed key */
    for (ix = 2U; ix < 2U + KBR_MAX_NBR_PRESSED; ix++) {
        if ((pbuf[ix] == 0x01U) || (pbuf[ix] == 0x02U) || (pbuf[ix] == 0x03U)) {
            error = TRUE;
        }
    }
    if (error == TRUE) {
        return;
    }
    nbr_keys     = 0U;
    nbr_keys_new = 0U;
    for (ix = 2U; ix < 2U + KBR_MAX_NBR_PRESSED; ix++) {
        if (pbuf[ix] != 0U) {
            keys[nbr_keys] = pbuf[ix];
            nbr_keys++;
            for (jx = 0U; jx < nbr_keys_last; jx++) {
                if (pbuf[ix] == keys_last[jx]) {
                    break;
                }
            }
            if (jx == nbr_keys_last) {
                keys_new[nbr_keys_new] = pbuf[ix];
                nbr_keys_new++;
            }
        }
    }
    if (nbr_keys_new == 1U) {
        key_newest = keys_new[0];

        if (shift == TRUE) {
            output = HID_KEYBRD_ShiftKey[HID_KEYBRD_Codes[key_newest]];
        } else {
            output = HID_KEYBRD_Key[HID_KEYBRD_Codes[key_newest]];
        }
        /* call user process handle */
        user_keyboard_dataprocess(output);
    } else {
        key_newest = 0x00U;
    }
    nbr_keys_last  = nbr_keys;
    for (ix = 0U; ix < KBR_MAX_NBR_PRESSED; ix++) {
        keys_last[ix] = keys[ix];
    }
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */

/*******************************************************************************
 * EOF (not truncated)
 ******************************************************************************/
